﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Medianamik.Core.Interfaces;
using System.Linq.Expressions;

namespace Medianamik.Core.Querying
{
    public static class QueryExtensions
    {
        public static TQ Where<TQ, TResult>(this TQ query, Guid pPropertyId, Comparison pComparison, IEnumerable<TResult> pValue)
        where TQ : IQuery
        {
            var prop = NodeTypeManager.GetTypeProperty(pPropertyId);
            if (prop == null)
            {
                throw new CoreException("Property Not Found : " + pPropertyId);
            }
            return Where(query, prop, pComparison, pValue);
        }

        public static TQ Where<TQ, TResult>(this TQ query, Guid pPropertyId, Comparison pComparison, TResult pValue)
        where TQ : IQuery
        {
            var prop = NodeTypeManager.GetTypeProperty(pPropertyId);
            if (prop == null)
            {
                throw new CoreException("Property Not Found : " + pPropertyId);
            }
            return Where(query, prop, pComparison, pValue);
        }

        //public static TQ Where<TQ,TResult>(this TQ query,MemberExpression pExpression,  Comparison pComp, TResult pValue )
        //where TQ : IQuery 
        //{
        //    query.Definition.NodeTypeWheres.Add(new NodeTypeWhere(pExpression, pComp, pValue));
        //    return query;
        //}

        public static TQ Where<TQ, TResult>(this TQ query, Expression<Func<IQueryableNode, TResult>> pExpression, Comparison pComparison, TResult pValue)
        where TQ : IQuery
        {
            if (pExpression.Body is MemberExpression)
            {
                query.Definition.NodeWheres.Add(new NodeWhere((MemberExpression)pExpression.Body, pComparison, pValue));
                return query;
            }
            throw new ArgumentException("Expression body must be a MemberExpression");
        }

        public static TQ Where<TQ, TResult>(this TQ query, Expression<Func<IQueryableNode, TResult>> pExpression, Comparison pComparison, IEnumerable<TResult> pValue)
            where TQ : IQuery
        {
            if (pExpression.Body is MemberExpression)
            {
                query.Definition.NodeWheres.Add(new NodeWhere((MemberExpression)pExpression.Body, pComparison, pValue));
                return query;
            }
            throw new ArgumentException("Expression body must be a MemberExpression");
        }

        public static TQ WhereType<TQ, TResult>(this TQ query, Expression<Func<IQueryableNodeType, TResult>> pExpression, Comparison pComparison, TResult pValue)
        where TQ : IQuery
        {
            if (pExpression.Body is MemberExpression)
            {
                query.Definition.NodeTypeWheres.Add(new NodeTypeWhere((MemberExpression)pExpression.Body, pComparison, pValue));
                return query;
            }
            throw new ArgumentException("Expression body must be a MemberExpression");
        }

        public static TQ WhereType<TQ, TResult>(this TQ query, Expression<Func<IQueryableNodeType, TResult>> pExpression, Comparison pComparison, IEnumerable<TResult> pValue)
        where TQ : IQuery
        {
            if (pExpression.Body is MemberExpression)
            {
                query.Definition.NodeTypeWheres.Add(new NodeTypeWhere((MemberExpression)pExpression.Body, pComparison, pValue));
                return query;
            }
            throw new ArgumentException("Expression body must be a MemberExpression");
        }

        public static TQ Where<TQ, TResult>(this TQ query, NodeTypeProperty pProperty, Comparison pComparison, IEnumerable<TResult> pValue)
        where TQ : IQuery
        {
            query.Definition.PropertyWheres.Add(new PropertyWhere(pProperty, pComparison, pValue));
            return query;
        }

        public static TQ Where<TQ, TResult>(this TQ query, NodeTypeProperty pProperty, Comparison pComparison, TResult pValue)
        where TQ : IQuery
        {
            query.Definition.PropertyWheres.Add(new PropertyWhere(pProperty, pComparison, pValue));
            return query;
        }

        public static TQ Skip<TQ>(this TQ query, int skipCount)
            where TQ : IQuery
        {
            query.Definition.SkipCount = skipCount;
            return query;
        }

        public static TQ Take<TQ>(this TQ query, int takeCount)
            where TQ : IQuery
        {
            query.Definition.TakeCount = takeCount;
            return query;
        }

        public static TQ HavingModification<TQ>(this TQ query, CultureInfo pCultureInfo)
            where TQ : IQuery
        {
            query.Definition.ModificationCulture = pCultureInfo;
            return query;
        }

        public static TQ SetFetchMode<TQ>(this TQ query, FetchMode pFetchMode )
            where TQ:IQuery 
        {
            switch(pFetchMode )
            {
                case  FetchMode.LazyLoadProperties:
                    query.Definition.LazyLoading = true;
                    break;
                case FetchMode.EagerLoadProperties:
                    query.Definition.LazyLoading = false;
                    break;
                default:
                    throw new NotImplementedException(); 
            }
            return query;
        }
        
    }
}
